package engine.gui;

import static org.lwjgl.opengl.GL11.*;

import org.lwjgl.input.Keyboard;

import engine.core.scene.Scene;
import engine.gui.popup.Popup;
import engine.gui.popup.PopupManager;
import engine.shader.GUIShader;
import engine.shader.Shader;
import engine.util.math.Matrix;

public class WindowManager {

	//the scene of the windowmanager
	private Scene scene;
	
	//the active component, if there is any. 
	private Component active;
	
	//the parent container, which contains the whole screen
	private Container parent;
	
	//the current size of the viewport
	private int width;
	private int height;
	
	//The used style
	private GUIStyle guiStyle;
	
	//The popup manager
	private PopupManager popupManager;
	
	//used projection matrix
	private Matrix projectionMatrix;
	private Shader guiShader;
	
	public WindowManager(int width, int height) {
		parent = new Container();
		parent.setWindowManager(this);
		parent.setWidth(width);
		parent.setHeight(height);
		parent.setSolid(false);
		
		this.width = width;
		this.height = height;
		
		popupManager = new PopupManager();
		
		projectionMatrix = new Matrix();
		
		guiShader = new GUIShader();
	}
	
	public void render() {
		preRender();
		
		parent.render(0, 0, width, height);
		
		popupManager.render();
		
		postRender();
	}
	
	private void preRender() {
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		
		projectionMatrix.ortho(0, width, height, 0, 0, 1);
		
		guiShader.enable();
		guiShader.sendUniform1i("useTexture", 1);
		guiShader.sendUniformMatrix4("projectionMatrix", projectionMatrix.toFloatBuffer());
		guiShader.sendUniformMatrix4("modelviewMatrix", Matrix.identity());
	}
	
	private void postRender() {	
		glDisable(GL_BLEND);
	}
	
	private void reset() {
		popupManager.reset();
		parent.reset();
	}
	
	public void updateView(int width, int height) {
		parent.setWidth(width);
		parent.setHeight(height);
		this.width = width;
		this.height = height;
	}
	
	public void addComponent(Component component) {
		parent.addComponent(component);
	}
	
	public void addPopup(Popup popup) {
		popupManager.addPopup(popup);
		popup.setWindowManager(this);
	}
	
	public boolean keyPressed(int key){
		if(key == Keyboard.KEY_RETURN && active != null) {
			active.activator();
			return true;
		}
		
		if(popupManager.keyPressed(key)) {
			return true;
		}
		
		return parent.keyPressed(key);
	}
	
	public boolean keyReleased(int key){
		if(popupManager.keyReleased(key)) {
			return true;
		}
		
		return parent.keyReleased(key);
	}
	
	public boolean mousePressed(int posX, int posY, int button) {
		posY = height - posY;
		active = null;
		
		if(popupManager.mousePressed(posX, posY, button)) {
			return true;
		}
		
		return parent.mousePressed(posX, posY, button);
	}
	
	public boolean mouseReleased(int posX, int posY, int button) {
		posY = height - posY;
		
		if(popupManager.mouseReleased(posX, posY, button)) {
			return true;
		}
		
		return parent.mouseReleased(posX, posY, button);
	}
	
	public boolean mouseMoved(int posX, int posY, int button) {
		reset();
		
		posY = height - posY;
		
		if(popupManager.mouseMoved(posX, posY, button)) {
			return true;
		}
		
		return parent.mouseMoved(posX, posY, button);
	}
	
	public boolean mouseDragged(int posX, int posY, int button) {
		reset();
		
		posY = height - posY;
		
		if(popupManager.mouseDragged(posX, posY, button)) {
			return true;
		}
		
		return parent.mouseDragged(posX, posY, button);
	}
	
	public boolean mouseWheelMoved(int movement) {
		if(popupManager.mouseWheelMoved(movement)) {
			return true;
		}
		
		return parent.mouseWheelMoved(movement);
	}
	
	public void setActive(Component active) {
		this.active = active;
	}
	
	public Component getActive() {
		return active;
	}
	
	public int getWidth() {
		return width;
	}
	
	public int getHeight() {
		return height;
	}
	
	public void setGuiStyle(GUIStyle guiStyle) {
		this.guiStyle = guiStyle;
	}
	
	public GUIStyle getGuiStyle() {
		return guiStyle;
	}
	
	public Shader getGuiShader() {
		return guiShader;
	}
	
	public void setScene(Scene scene) {
		this.scene = scene;
	}
	
	public Scene getScene() {
		return scene;
	}
}
